package com.jyw.business.ins.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.jyw.business.ins.domain.InsPlan;
import com.jyw.business.ins.domain.InsPlanExecutionTime;
import com.jyw.business.ins.domain.InsPlanSkip;
import com.jyw.business.ins.domain.model.CreateTaskDays;
import com.jyw.business.ins.domain.model.CreateTaskTimeRage;
import com.jyw.business.ins.domain.model.CreateTaskWeek;
import com.jyw.business.ins.domain.vo.web.InsPlanItemVO;
import com.jyw.business.ins.enums.InsPlanSkipEnum;
import com.jyw.business.ins.enums.InspectionCycleEnum;
import com.jyw.business.ins.service.*;
import com.jyw.business.ins.task.InspectionTaskUtil;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Period;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author Created by ZhangCheng on 2023/10/11 （巡检定时任务）
 */
@Service
public class IInsTaskJobServiceImpl implements IInsTaskJobService {

    @Resource
    private IInsPlanService insPlanService;

    @Resource
    private IInsPlanExecutionTimeService executionTimeService;

    @Resource
    private IInsPlanItemService insPlanItemService;

    @Resource
    private IInsTaskService insTaskService;

    @Resource
    private IInsPlanSkipService insPlanSkipService;

    /**
     * 判断是否已生成
     */
    @Override
    public void createInsTask() {
        List<InsPlan> planList = insPlanService.queryPlanTaskList();
        if (CollUtil.isNotEmpty(planList)) {
            // 当前生成日期
            LocalDateTime minDateTime = LocalDateTimeUtil.beginOfDay(LocalDateTime.now());
            planList.forEach(plan -> {
                createInsTaskByDate(plan, minDateTime);
            });
        }
    }

    @Override
    public void createInsTaskByDate(InsPlan insPlan, LocalDateTime localDateTime) {
        if (insPlan.getInspectionCycle() != null) {
            int cycle = insPlan.getInspectionCycle();
            //每天
            if (InspectionCycleEnum.EVERY_DAY.getValue() == cycle) {
                everyDay(insPlan, localDateTime);
            }
            //每周
            if (InspectionCycleEnum.WEEKLY.getValue() == cycle) {
                weekly(insPlan, localDateTime);
            }
            //每月
            if (InspectionCycleEnum.EVERY_MONTH.getValue() == cycle) {
                everyMonth(insPlan, localDateTime);
            }
            //每季度
            if (InspectionCycleEnum.EVERY_QUARTER.getValue() == cycle) {
                everyQuarter(insPlan, localDateTime);
            }
            //每半年
            if (InspectionCycleEnum.SEMI_ANNUAL.getValue() == cycle) {
                semiAnnual(insPlan, localDateTime);
            }
            //每年
            if (InspectionCycleEnum.EVERY_YEAR.getValue() == cycle) {
                everyYear(insPlan, localDateTime);
            }
        }
    }

    /**
     * 每天
     *
     * @param insPlan
     * @param currentTime
     */
    public void everyDay(InsPlan insPlan, LocalDateTime currentTime) {
        int createType = isCreateType(insPlan, currentTime);
        // 今天需要生成 每天生成则不需要处理储存任务，【1.次日有任务，则不生成节假日/周末的任务】【2.次日没有任务，则生成节假日/周末的任务】
        if (createType == InsPlanSkipEnum.HANDLE.getValue()) {
            // 获取任务生成时间
            List<CreateTaskTimeRage> timeRages = getExecutionTime(insPlan, currentTime);
            // 生成定时任务
            createTaskByDate(timeRages, insPlan, currentTime);
        }
    }

    /**
     * 每周
     *
     * @param insPlan
     * @param currentTime
     */
    public void weekly(InsPlan insPlan, LocalDateTime currentTime) {
        Long planId = insPlan.getId();
        LocalDate localDate = currentTime.toLocalDate();
        int dayOfWeek = LocalDateTimeUtil.dayOfWeek(localDate).getIso8601Value();
        // 巡检次数
        int inspectionNum = insPlan.getInspectionNum() == null ? 1 : insPlan.getInspectionNum();
        List<CreateTaskWeek> taskWeeks = InspectionTaskUtil.getWeeklyNum(inspectionNum, insPlan.getWeekly());
        CreateTaskWeek taskWeek = taskWeeks.stream().filter(a -> a.getWeek().intValue() == dayOfWeek && a.getNum() > 0).findFirst().orElse(null);
        // 判断每周生成的天数中今天是否包含
        if (taskWeek != null) {
            LocalDate monday = localDate.minusDays(dayOfWeek - 1);
            List<InsPlanExecutionTime> timeList = null;
            // 固定时间
            if (insPlan.getIsFixedTime() != null && insPlan.getIsFixedTime()) {
                timeList = getPlanExecutionTime(insPlan.getId());
            }
            List<CreateTaskWeek> filterWeeks = InspectionTaskUtil.getWeekTaskTime(taskWeeks, timeList, inspectionNum, monday);
            CreateTaskWeek executeWeek = filterWeeks.stream().filter(a -> a.getWeek().intValue() == dayOfWeek && CollUtil.isNotEmpty(a.getTimeRages())).findFirst().orElse(null);
            // 今天是执行天
            if (executeWeek != null) {
                int createType = isCreateType(insPlan, currentTime);
                // 获取任务生成时间
                List<CreateTaskTimeRage> timeRages = executeWeek.getTimeRages();
                if (createType == InsPlanSkipEnum.HANDLE.getValue()) {
                    // 生成定时任务
                    createTaskByDate(timeRages, insPlan, currentTime);
                } else if (createType == InsPlanSkipEnum.WEEKEND.getValue()) {
                    LocalDateTime notWeekend = InspectionTaskUtil.lastNotWeekend(currentTime);
                    if (notWeekend != null) {
                        // 生成跳过任务记录
                        saveNewSkipTask(planId, timeRages, notWeekend, InsPlanSkipEnum.WEEKEND.getValue());
                    }
                } else if (createType == InsPlanSkipEnum.HOLIDAY.getValue()) {
                    LocalDateTime notHoliday = InspectionTaskUtil.lastNotHoliday(currentTime);
                    if (notHoliday != null) {
                        // 生成跳过任务记录
                        saveNewSkipTask(planId, timeRages, notHoliday, InsPlanSkipEnum.HOLIDAY.getValue());
                    }
                }
            }
        }
        // 判断是否有跳过任务生成
        createPlanSkip(insPlan, currentTime);
    }

    /**
     * 每月
     *
     * @param insPlan
     * @param currentTime
     */
    public void everyMonth(InsPlan insPlan, LocalDateTime currentTime) {
        Long planId = insPlan.getId();
        // 巡检次数
        int inspectionNum = insPlan.getInspectionNum() == null ? 1 : insPlan.getInspectionNum();
        LocalDate localDate = currentTime.toLocalDate();
        int dayOfMonth = localDate.getDayOfMonth();
        List<CreateTaskDays> taskMonths = InspectionTaskUtil.getMonthlyNum(inspectionNum, insPlan.getMonthly(), localDate);
        CreateTaskDays taskMonth = taskMonths.stream().filter(a -> a.getDay().intValue() == dayOfMonth && a.getNum() > 0).findFirst().orElse(null);
        if (taskMonth != null) {
            LocalDate firstDate = localDate.withDayOfMonth(1);
            List<InsPlanExecutionTime> timeList = getPlanExecutionTime(planId);
            List<CreateTaskDays> filterMonths = InspectionTaskUtil.getMonthTaskTime(taskMonths, timeList, inspectionNum, firstDate);
            CreateTaskDays executeDay = filterMonths.stream().filter(a -> a.getDay().intValue() == dayOfMonth && CollUtil.isNotEmpty(a.getTimeRages())).findFirst().orElse(null);
            // 今天是执行天
            if (executeDay != null) {
                int createType = isCreateType(insPlan, currentTime);
                // 获取任务生成时间
                List<CreateTaskTimeRage> timeRages = executeDay.getTimeRages();
                if (createType == InsPlanSkipEnum.HANDLE.getValue()) {
                    // 生成定时任务
                    createTaskByDate(timeRages, insPlan, currentTime);
                } else if (createType == InsPlanSkipEnum.WEEKEND.getValue()) {
                    LocalDateTime notWeekend = InspectionTaskUtil.lastNotWeekend(currentTime);
                    if (notWeekend != null) {
                        // 生成跳过任务记录
                        saveNewSkipTask(planId, timeRages, notWeekend, InsPlanSkipEnum.WEEKEND.getValue());
                    }
                } else if (createType == InsPlanSkipEnum.HOLIDAY.getValue()) {
                    LocalDateTime notHoliday = InspectionTaskUtil.lastNotHoliday(currentTime);
                    if (notHoliday != null) {
                        // 生成跳过任务记录
                        saveNewSkipTask(planId, timeRages, notHoliday, InsPlanSkipEnum.HOLIDAY.getValue());
                    }
                }
            }
        }
        // 判断是否有跳过任务生成
        createPlanSkip(insPlan, currentTime);
    }

    /**
     * 每季度
     *
     * @param insPlan
     * @param currentTime
     */
    public void everyQuarter(InsPlan insPlan, LocalDateTime currentTime) {
        List<String> allDays = InspectionTaskUtil.getAllDays(InspectionTaskUtil.QUARTER_DAY);
        createByDays(insPlan, currentTime, allDays);
    }

    /**
     * 每半年
     *
     * @param insPlan
     * @param currentTime
     */
    public void semiAnnual(InsPlan insPlan, LocalDateTime currentTime) {
        List<String> allDays = InspectionTaskUtil.getAllDays(InspectionTaskUtil.ANNUAL_DAY);
        createByDays(insPlan, currentTime, allDays);
    }

    /**
     * 每年
     *
     * @param insPlan
     * @param currentTime
     */
    public void everyYear(InsPlan insPlan, LocalDateTime currentTime) {
        List<String> allDays = InspectionTaskUtil.getAllDays(InspectionTaskUtil.YEAR_DAY);
        createByDays(insPlan, currentTime, allDays);
    }

    /**
     * 按生产总天数生成巡检计划
     *
     * @param insPlan
     * @param currentTime
     * @param allDays
     */
    public void createByDays(InsPlan insPlan, LocalDateTime currentTime, List<String> allDays) {
        Long planId = insPlan.getId();
        // 巡检次数
        int inspectionNum = insPlan.getInspectionNum() == null ? 1 : insPlan.getInspectionNum();
        LocalDate localDate = currentTime.toLocalDate();
        LocalDate startDate = insPlan.getEffectiveStartDate();
        Period period = Period.between(startDate, localDate);
        int days = (period.getDays()+1);
        List<CreateTaskDays> taskMonths = InspectionTaskUtil.getAllDaysNum(inspectionNum, allDays);
        CreateTaskDays taskDays = taskMonths.stream().filter(a -> a.getDay().intValue() == days && a.getNum() > 0).findFirst().orElse(null);
        if (taskDays != null) {
            List<InsPlanExecutionTime> timeList = getPlanExecutionTime(planId);
            List<CreateTaskDays> filterDays = InspectionTaskUtil.getMonthTaskTime(taskMonths, timeList, inspectionNum, startDate);
            CreateTaskDays executeDay = filterDays.stream().filter(a -> a.getDay().intValue() == days && CollUtil.isNotEmpty(a.getTimeRages())).findFirst().orElse(null);
            // 今天是执行天
            if (executeDay != null) {
                int createType = isCreateType(insPlan, currentTime);
                // 获取任务生成时间
                List<CreateTaskTimeRage> timeRages = executeDay.getTimeRages();
                if (createType == InsPlanSkipEnum.HANDLE.getValue()) {
                    // 生成定时任务
                    createTaskByDate(timeRages, insPlan, currentTime);
                } else if (createType == InsPlanSkipEnum.WEEKEND.getValue()) {
                    LocalDateTime notWeekend = InspectionTaskUtil.lastNotWeekend(currentTime);
                    if (notWeekend != null) {
                        // 生成跳过任务记录
                        saveNewSkipTask(planId, timeRages, notWeekend, InsPlanSkipEnum.WEEKEND.getValue());
                    }
                } else if (createType == InsPlanSkipEnum.HOLIDAY.getValue()) {
                    LocalDateTime notHoliday = InspectionTaskUtil.lastNotHoliday(currentTime);
                    if (notHoliday != null) {
                        // 生成跳过任务记录
                        saveNewSkipTask(planId, timeRages, notHoliday, InsPlanSkipEnum.HOLIDAY.getValue());
                    }
                }
            }
        }
        // 判断是否有跳过任务生成
        createPlanSkip(insPlan, currentTime);
    }


    /**
     * 获取任务生成时间
     *
     * @param insPlan
     * @param currentTime
     * @return
     */
    public List<CreateTaskTimeRage> getExecutionTime(InsPlan insPlan, LocalDateTime currentTime) {
        List<InsPlanExecutionTime> timeList = null;
        // 固定时间
        if (insPlan.getIsFixedTime() != null && insPlan.getIsFixedTime()) {
            timeList = getPlanExecutionTime(insPlan.getId());
        }
        // 巡检次数
        int num = insPlan.getInspectionNum() == null ? 1 : insPlan.getInspectionNum();
        List<CreateTaskTimeRage> timeRages = InspectionTaskUtil.getDayTaskTime(timeList, currentTime, num);
        return timeRages;
    }

    /**
     * 获取巡检计划固定时间
     *
     * @param planId
     * @return
     */
    public List<InsPlanExecutionTime> getPlanExecutionTime(Long planId) {
        return executionTimeService.selectByPlanId(planId);
    }

    /**
     * 获取巡检计划生成状态
     *
     * @param insPlan
     * @return
     */
    public Integer isCreateType(InsPlan insPlan, LocalDateTime dateTime) {
        // 是周末
        if (InspectionTaskUtil.checkWeekend(dateTime)) {
            //跳过周末
            if (insPlan.getSkipWeekend() != null && insPlan.getSkipWeekend()) {
                // 次日处理
                if (insPlan.getProcessingRule() != null && insPlan.getProcessingRule().intValue() == 2) {
                    // 可生成周末任务
                    return InsPlanSkipEnum.WEEKEND.getValue();
                }
            } else {
                // 不跳过周末直接生成
                return InsPlanSkipEnum.HANDLE.getValue();
            }
        } else if (InspectionTaskUtil.checkHoliday(dateTime)) {
            // 是节假日 跳过节假日
            if (insPlan.getSkipHoliday() != null && insPlan.getSkipHoliday()) {
                // 次日处理
                if (insPlan.getProcessingRule() != null && insPlan.getProcessingRule().intValue() == 2) {
                    // 可生成节假日任务
                    return InsPlanSkipEnum.HOLIDAY.getValue();
                }
            } else {
                // 不跳过节假日直接生成
                return InsPlanSkipEnum.HANDLE.getValue();
            }
        } else {
            // 不是节假日和周末
            return InsPlanSkipEnum.HANDLE.getValue();
        }
        // 其余为跳过
        return InsPlanSkipEnum.SKIP.getValue();
    }

    /**
     * 生成巡检任务
     *
     * @param timeRages
     * @param insPlan
     * @param currentTime
     */
    public void createTaskByDate(List<CreateTaskTimeRage> timeRages, InsPlan insPlan, LocalDateTime currentTime) {
        if (CollUtil.isNotEmpty(timeRages)) {
            Long planId = insPlan.getId();
            List<CreateTaskTimeRage> filterList = timeRages.stream().filter(a -> a.getStartTime().isAfter(currentTime) ||
                    a.getStartTime().isEqual(currentTime)).collect(Collectors.toList());
            // 需要重新生成的任务
            if (CollUtil.isNotEmpty(filterList)) {
                List<InsPlanItemVO> planItems = insPlanItemService.getPlanItemList(planId);
                insTaskService.deleteCreateTask(planId, currentTime);
                insTaskService.createInsTask(insPlan, planItems, filterList);
                // 清空已生成存储任务
                insPlanSkipService.deleteSkipTask(planId, currentTime.toLocalDate());
            }
        }
    }

    /**
     * 生成新的跳过任务
     *
     * @param planId
     * @param timeRages
     * @param localDateTime
     * @param skipType
     */
    public void saveNewSkipTask(Long planId, List<CreateTaskTimeRage> timeRages, LocalDateTime localDateTime, Integer skipType) {
        LocalDate localDate = localDateTime.toLocalDate();
        // 清空已生成存储任务
        insPlanSkipService.deleteSkipTask(planId, localDate);
        if (CollUtil.isNotEmpty(timeRages)) {
            timeRages.forEach(timeRage -> {
                LocalTime startTime = timeRage.getStartTime().toLocalTime();
                LocalTime endTime = timeRage.getEndTime().toLocalTime();
                timeRage.setStartTime(localDate.atTime(startTime));
                timeRage.setEndTime(localDate.atTime(endTime));
            });
            // 生成跳过任务记录
            insPlanSkipService.saveSkipTask(planId, localDate, skipType, timeRages);
        }
    }

    /**
     * 判断是否生成跳过任务
     *
     * @param insPlan
     * @param currentTime
     */
    public void createPlanSkip(InsPlan insPlan, LocalDateTime currentTime) {
        List<InsPlanSkip> planSkips = insPlanSkipService.findSkipTask(insPlan.getId(), currentTime.toLocalDate());
        if (CollUtil.isNotEmpty(planSkips)) {
            InsPlanSkip insPlanSkip = planSkips.get(0);
            if (StrUtil.isNotEmpty(insPlanSkip.getSkipTask())) {
                List<CreateTaskTimeRage> timeRages = JSON.parseArray(insPlanSkip.getSkipTask(), CreateTaskTimeRage.class);
                // 生成定时任务
                createTaskByDate(timeRages, insPlan, currentTime);
            }
        }
    }

    public static void main(String[] args) {
        int inspectionNum = 30;
        LocalDateTime currentTime = LocalDateTimeUtil.parse("2023-12-26T00:00:00");
        LocalDate localDate = currentTime.toLocalDate();
        LocalDate startDate = LocalDateTimeUtil.parseDate("2023-12-20");
        Period period = Period.between(startDate, localDate);
        int days = (period.getDays()+1);
        System.out.println(days);
        List<String> allDays = InspectionTaskUtil.getAllDays(InspectionTaskUtil.QUARTER_DAY);
        List<CreateTaskDays> taskMonths = InspectionTaskUtil.getAllDaysNum(inspectionNum, allDays);
        taskMonths.forEach(a -> System.out.println(a));
        CreateTaskDays taskDays = taskMonths.stream().filter(a -> a.getDay().intValue() == days && a.getNum() > 0).findFirst().orElse(null);
        if (taskDays != null) {
            System.out.println("taskMonth==" + taskDays);
            List<InsPlanExecutionTime> timeList = null;
            List<CreateTaskDays> filterDays = InspectionTaskUtil.getMonthTaskTime(taskMonths, timeList, inspectionNum, startDate);
            CreateTaskDays executeMonth = filterDays.stream().filter(a -> a.getDay().intValue() == days && CollUtil.isNotEmpty(a.getTimeRages())).findFirst().orElse(null);
            filterDays.forEach(a -> System.out.println(a));
            // 今天是执行天
            if (executeMonth != null) {
                System.out.println("executeMonth==" + executeMonth);
            }
        }

    }

}
